<!DOCTYPE html>



  


<html class="theme-next gemini use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon32.ico?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon16.ico?v=5.1.4">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="编程,Java,JUC,多线程," />





  <link rel="alternate" href="/rss2.xml" title="老苏叶的小窝" type="application/atom+xml" />






<meta name="description" content="进程、线程、纤程（携程）什么是进程？专业说法：在操作系统中，进程是最基本的资源单位，操作系统通过进程来管理计算机操作资源，如CPU、内存、磁盘等。每一个进程都有一个唯一的进程标识符（PID），用于区分不同的进程。 通俗说话：可以看作正在执行的程序，如QQ.exe等 在Java中，当我们启动main函数时其实就是启动了一个JVM的进程，而mian函数所在的线程就是这个进程中的一个线程，也称主线程">
<meta property="og:type" content="article">
<meta property="og:title" content="JUC学习笔记（一）">
<meta property="og:url" content="https://gitee.com/laosuye/laosuye.git/2024/09/20/JUC%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B8%80%EF%BC%89/index.html">
<meta property="og:site_name" content="老苏叶的小窝">
<meta property="og:description" content="进程、线程、纤程（携程）什么是进程？专业说法：在操作系统中，进程是最基本的资源单位，操作系统通过进程来管理计算机操作资源，如CPU、内存、磁盘等。每一个进程都有一个唯一的进程标识符（PID），用于区分不同的进程。 通俗说话：可以看作正在执行的程序，如QQ.exe等 在Java中，当我们启动main函数时其实就是启动了一个JVM的进程，而mian函数所在的线程就是这个进程中的一个线程，也称主线程">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726275943754-fe64ee1b-08cd-4cd0-9a9a-aa99554da168.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726282418135-28827dde-6271-4006-9c80-ea687fbfe784.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726814478434-703be79a-c5db-48d1-8fce-be112314bb32.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726814632040-0ab55f30-f994-4cf6-a8dd-866740250c8f.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726814740885-2a47eae2-0a41-4a6d-9214-6d62a798bae9.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726817318884-a780f06f-a6f4-47a0-a848-0fbc2b4e0f70.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726817976227-6e81e8ea-45d7-4232-946f-d642610e11e6.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726819000502-c0e8f486-6782-4df7-9904-72154a17f9ac.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726819262013-ae4fcb55-8680-48c5-9edc-32c6292db969.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726819340723-cf47d9a5-f1e9-4106-ae79-b0ccbd511f48.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726819507586-e0ce7c70-c994-4361-8d81-ec41d95a8810.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726819587869-1db54234-9bec-4d8b-81cb-eb23c4ef72ee.png">
<meta property="article:published_time" content="2024-09-20T08:41:48.000Z">
<meta property="article:modified_time" content="2024-09-20T08:42:13.029Z">
<meta property="article:author" content="老苏叶">
<meta property="article:tag" content="编程">
<meta property="article:tag" content="Java">
<meta property="article:tag" content="JUC">
<meta property="article:tag" content="多线程">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726275943754-fe64ee1b-08cd-4cd0-9a9a-aa99554da168.png">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Gemini',
    version: '5.1.4',
    sidebar: {"position":"right","display":"post","offset":12,"b2t":false,"scrollpercent":true,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://gitee.com/laosuye/laosuye.git/2024/09/20/JUC学习笔记（一）/"/>





  <title>JUC学习笔记（一） | 老苏叶的小窝</title>
  





  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?e8f796a0dc919d18055bb061f82a6395";";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




<meta name="generator" content="Hexo 4.2.0"></head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-right page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">老苏叶的小窝</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      

      
        <li class="menu-item menu-item-search">
          
            <a href="javascript:;" class="popup-trigger">
          
            
              <i class="menu-item-icon fa fa-search fa-fw"></i> <br />
            
            搜索
          </a>
        </li>
      
    </ul>
  

  
    <div class="site-search">
      
  <div class="popup search-popup local-search-popup">
  <div class="local-search-header clearfix">
    <span class="search-icon">
      <i class="fa fa-search"></i>
    </span>
    <span class="popup-btn-close">
      <i class="fa fa-times-circle"></i>
    </span>
    <div class="local-search-input-wrapper">
      <input autocomplete="off"
             placeholder="搜索..." spellcheck="false"
             type="text" id="local-search-input">
    </div>
  </div>
  <div id="local-search-result"></div>
</div>



    </div>
  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://gitee.com/laosuye/laosuye.git/2024/09/20/JUC%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B8%80%EF%BC%89/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="老苏叶">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatra.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="老苏叶的小窝">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">JUC学习笔记（一）</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2024-09-20T16:41:48+08:00">
                2024-09-20
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E7%BC%96%E7%A8%8B/" itemprop="url" rel="index">
                    <span itemprop="name">编程</span>
                  </a>
                </span>

                
                
                  ， 
                
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E7%BC%96%E7%A8%8B/Java/" itemprop="url" rel="index">
                    <span itemprop="name">Java</span>
                  </a>
                </span>

                
                
                  ， 
                
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E7%BC%96%E7%A8%8B/Java/JUC/" itemprop="url" rel="index">
                    <span itemprop="name">JUC</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2024/09/20/JUC%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B8%80%EF%BC%89/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count valine-comment-count" data-xid="/2024/09/20/JUC%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B8%80%EF%BC%89/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          
            <span class="post-meta-divider">|</span>
            <span class="page-pv"><i class="fa fa-file-o"></i> 浏览
            <span class="busuanzi-value" id="busuanzi_value_page_pv" ></span>次
            </span>
          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">字数统计&#58;</span>
                
                <span title="字数统计">
                  7.8k 字
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                
                <span title="阅读时长"> 分钟
                  30
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <meta name="referrer" content="no-referrer">

<h2 id="进程、线程、纤程（携程）"><a href="#进程、线程、纤程（携程）" class="headerlink" title="进程、线程、纤程（携程）"></a>进程、线程、纤程（携程）</h2><h3 id="什么是进程？"><a href="#什么是进程？" class="headerlink" title="什么是进程？"></a>什么是进程？</h3><p><strong>专业说法：</strong>在操作系统中，进程是最基本的资源单位，操作系统通过进程来管理计算机操作资源，如CPU、内存、磁盘等。每一个进程都有一个唯一的进程标识符（PID），用于区分不同的进程。</p>
<p><strong>通俗说话：</strong>可以看作正在执行的程序，如QQ.exe等</p>
<p>在Java中，当我们启动main函数时其实就是启动了一个JVM的进程，而mian函数所在的线程就是这个进程中的一个线程，也称主线程。</p>
<p>如下图所示，在Windows中通过查看任务管理器的方式，我们就可以清楚看到Windows当前运行的进程（<code>&lt;font style=&quot;color:rgb(44, 62, 80);&quot;&gt;.exe&lt;/font&gt;</code>文件的运行）</p>
<p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726275943754-fe64ee1b-08cd-4cd0-9a9a-aa99554da168.png" alt></p>
<h3 id="什么是线程？"><a href="#什么是线程？" class="headerlink" title="什么是线程？"></a>什么是线程？</h3><p>线程和进程相似，但是线程是比进程更小的执行单位，一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享进程的<strong>堆</strong>和<strong>方法区</strong>资源，但是每个线程有自己的<strong>程序计数器</strong>，<strong>虚拟机栈</strong>和<strong>本地方法栈，</strong>所以系统在产生了一个线程，或者是在多个线程之前做切换工作时，负担比进程小的多，也正因为如此，线程也被称为轻量级进程。</p>
<p>同一时刻，一个CPU核心只能运行一个线程，也就是CPU内核和同时运行的线程数量是1:1的关系，也就是说8核CPU同时可以执行8个线程的代码。</p>
<p>通俗来说：线程可以理解为一个饭店的饭桌，每个饭桌可以点不同的菜，但是都可以共享饭店服务员，厨师，饭店的多少决定客户的处理效率。‘</p>
<p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726282418135-28827dde-6271-4006-9c80-ea687fbfe784.png" alt></p>
<h3 id="什么是纤程（协程）？"><a href="#什么是纤程（协程）？" class="headerlink" title="什么是纤程（协程）？"></a>什么是纤程（协程）？</h3><p>底层角度：</p>
<ul>
<li>纤程可以在一个线程内创建多个纤程，这些纤程之间可以共享同一个线程的资源。</li>
<li>纤程是在同一个进程内部运行的，不需要操作系统的介入，可以在用户空间内实现协作式多任务处理。因此纤程的创建和销毁开销很小，可以更高效的利用系统资源。</li>
</ul>
<p>通俗角度：通俗的说，如果线程是饭店的饭桌，携程就是座椅</p>
<p>Java19才支持虚拟线程（纤程）或者使用第三方协程库quasar</p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ul>
<li>先有进程，然后进程可以创建线程，线程是依附在进程里面的，线程里面可以包含多个协程</li>
<li>进程之间不共享全局变量，线程之间共享全局变量，但是要注意资源竞争问题</li>
</ul>
<h2 id="并行、并发、串行"><a href="#并行、并发、串行" class="headerlink" title="并行、并发、串行"></a>并行、并发、串行</h2><p>我们举个例子，饭店的客户是线程，菜单是指令，厨师是CPU</p>
<h3 id="并发"><a href="#并发" class="headerlink" title="并发"></a>并发</h3><p><strong>通俗：</strong>并发是多个客户在<strong>同一时间段</strong>不约而同的来到饭店，都想快点上菜，却只有一个厨师，厨师想了个办法，给每一桌上一个菜，然后再轮流炒第二第三个菜。。。达到雨露均沾，不至于后面来的厨师闹情绪。</p>
<p><strong>底层：</strong>在操作系统中，安装多个程序，并发的是<strong>同一时间段</strong>内，宏观是有多个程序同时运行，这在单系统的CPU系统中，每一刻只能有一道程序执行，即微观上这些程序是分时的<strong>交替运行</strong>，只不过给人的感觉是同时运行，那是因为交替运行的时间是非常短的。</p>
<h3 id="并行"><a href="#并行" class="headerlink" title="并行"></a>并行</h3><p><strong>通俗：</strong>并行是多个客户同一时刻一起来到了饭店，没人愿意排队，但是饭店有多个厨师，每桌安排一个厨师，这就是并行</p>
<p><strong>底层：</strong>在<strong>多核CPU</strong>系统中，这些<strong>同一时刻</strong>的程序可以分配到多个处理器上（CPU），实现多任务并行执行，即利用每个处理器来处理一个可以并发执行的程序，这样可以使多个程序同时执行，目前电脑上的多核CPU，便是多核处理器，核越多，并行处理的程序越多，能大大提高电脑运行的效率。</p>
<h3 id="串行"><a href="#串行" class="headerlink" title="串行"></a>串行</h3><p><strong>通俗：</strong>串行就比较好理解了，简单来说就是根据先后顺序来，先到先得，厨师根据点单顺序来做菜</p>
<p><strong>底层：</strong>如单核CPU，同一时刻只能运行一个程序，如果存在多个程序，需要根据先后顺序执行，例如，打开QQ后不能再同时打开微信，只能等qq执行完毕（关闭）后打开微信，线程的串行亦是如此，一次只能执行一个线程代码指令，其他线程需要排队等候。</p>
<h3 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h3><p>并发<strong>Concurrent：</strong>指应用能够交替执行不同的任务，比如单核CPU核心下执行多线程并非是同时执行多个任务如果你开两个线程执行，就是在你几乎不可察觉到的速度下不断切换这两个任务而已，已达到“同时执行”的效果，真实并不是，只是计算机执行的速度太快，我们无法察觉到。</p>
<p>并行<strong>Parallel：</strong>指应用能够同时执行不同的任务，例如：吃饭的时候可以边吃饭边打电话，这两件事是可以同时执行的</p>
<p>串行<strong>Serial：</strong>一个一个排队执行</p>
<p>两者的区别是：一个交替执行，一个同时执行。</p>
<h3 id="CPU的核心数和线程数的关系"><a href="#CPU的核心数和线程数的关系" class="headerlink" title="CPU的核心数和线程数的关系"></a>CPU的核心数和线程数的关系</h3><p>目前主流的CPU都是多核的，线程是CPU调度的最小单位，同一时刻，一个CPU只能运行一个线程，也就是CPU内核和同时运行的线程数是1：1的关系，也就是说8核CPU同时可以执行8个线程的代码，但是Inter引入超线程技术后，产生了逻辑处理器的概念，使核心数和线程数形成了1：2的关系，内核6而逻辑处理器数量是12。</p>
<p>在Java中提供了<code>Runtime.getRuntime().availableProcessors()</code>,可以让我们获取当前CPU的核心，记住这个核心指的是逻辑处理数。</p>
<p>获得CPU的核心数在并发编程中很重要，并发编程的性能优化往往和CPU的核心数密切相关。</p>
<h3 id="上下文切换（Context-switch）"><a href="#上下文切换（Context-switch）" class="headerlink" title="上下文切换（Context switch）"></a>上下文切换（Context switch）</h3><p>由于现在大多数计算机都是多核CPU，多线程往往会比单线程更快，更能够提高并发，但提高并发并不意味着启动更多的线程来执行，更多的线程意味着线程创建销毁开销更大，上下文非常频繁，你的程序反而不能支持更高的TPS。</p>
<p><strong>时间片</strong></p>
<p>多任务系统往往需要同时执行多道作业，作业往往大于机器的CPU数，然后一颗CPU同时只能够执行一项任务，如何让用户感觉这些任务正在同时执行呢？操作系统的设计者巧妙地利用了时间片轮转的方式</p>
<p>时间片是CPU分配给各个任务（线程）的时间！</p>
<p>时间片是CPU分配给各个任务（线程）的时间！</p>
<p><font style="background-color:#D9EAFC;">思考：单核CPU为何也支持多线程呢？</font></p>
<p><font style="background-color:#D9EAFC;"></font></p>
<blockquote>
<p>单核 CPU 支持多线程是通过 时间片轮转（time slicing） 和 上下文切换（context switching） 来实现的，而不是同时执行多个线程。以下是单核 CPU 支持多线程的原因：</p>
<ol>
<li>时间片轮转<br>操作系统为每个线程分配了一个非常短的时间片（通常为几毫秒），在时间片内该线程独占 CPU 运行。时间片结束后，操作系统会暂停当前线程并切换到下一个线程执行。由于时间片非常短，在人类感知上会感觉多个线程同时运行，但实际上它们是分时运行的。</li>
<li>上下文切换<br>当 CPU 切换到另一个线程时，它会保存当前线程的状态（比如寄存器的值、程序计数器等），然后加载另一个线程的状态。这个过程称为 上下文切换。虽然上下文切换会有一定的开销，但它使得单核 CPU 能够处理多个任务。</li>
</ol>
</blockquote>
<p>线程上下文是指某一时间点CPU寄存器和程序计数器的内容，CPU通过时间片分配算法来循环执行任务（线程），因为时间片非常的短，所以CPU通过不停的切换线程执行。</p>
<p>换言之，单CPU这么频繁，多核CPU可以一定程度上可以减少上下文切换。</p>
<p><strong>总结</strong></p>
<ul>
<li>（单核CPU）同一时间，CPU只能处理一个线程，只有一个线程在执行。</li>
<li>多线程同时执行：是CPU快速的在多个线程直线切换</li>
<li>CPU调度线程的时间足够快，就造成了多个线程“同时”执行</li>
<li>如果线程数非常多，CPU会在n个线程之间切换，消耗了大量的CPU资源</li>
<li>每个线程的调度次数会降低，线程的执行效率降低</li>
</ul>
<p><strong>建议</strong></p>
<p>合理的设置线程数目即可以最大化利用CPU，又可以减少线程切换的开销</p>
<ul>
<li>高并发，低耗时的情况，建议少线程</li>
<li>低并发，高耗时的情况，建议多线程</li>
<li>高并发高耗时，要分析任务类型，增加排队，加大线程数</li>
</ul>
<h2 id="创建线程"><a href="#创建线程" class="headerlink" title="创建线程"></a>创建线程</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//通过继承Thread类</span></span><br><span class="line">        MyThread myThread = <span class="keyword">new</span> MyThread();</span><br><span class="line">        <span class="comment">//开启线程</span></span><br><span class="line">        myThread.start();</span><br><span class="line">        <span class="comment">//通过实现Runnable接口</span></span><br><span class="line">        Thread thread = <span class="keyword">new</span> Thread(<span class="keyword">new</span> MyRunnable());</span><br><span class="line">        <span class="comment">//开启线程</span></span><br><span class="line">        thread.start();</span><br><span class="line">        System.out.println(<span class="string">"main方法"</span>);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h3 id="继承Thread"><a href="#继承Thread" class="headerlink" title="继承Thread"></a>继承Thread</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyThread</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"继承Thread类方法"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="实现Runnable"><a href="#实现Runnable" class="headerlink" title="实现Runnable"></a>实现Runnable</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyRunnable</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"实现Runnable接口方法"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="匿名内部类方式"><a href="#匿名内部类方式" class="headerlink" title="匿名内部类方式"></a>匿名内部类方式</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">createThread</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Thread thread = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                System.out.println(<span class="string">"Runnable 匿名内部类方式创建线程"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        thread.start();</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h4 id="Lambda方式"><a href="#Lambda方式" class="headerlink" title="Lambda方式"></a>Lambda方式</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">createThread2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Thread thread = <span class="keyword">new</span> Thread(() -&gt; System.out.println(<span class="string">"Runnable lambda表达式创建线程"</span>));</span><br><span class="line">        thread.start();</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h3 id="线程执行的原理"><a href="#线程执行的原理" class="headerlink" title="线程执行的原理"></a>线程执行的原理</h3><p>我们看到，⽆论以哪种⽅式创建，最终我们都会重写⼀个叫做 run 的⽅法，来处理我们的业务逻辑，然</p>
<p>⽽我们都是调⽤⼀个start⽅法，来启动⼀个线程；</p>
<p>那 start⽅法和run⽅法之间是⼀个什么关系呢？从后边的介绍我们将获得这样⼀个信息：run就是⼀个回调函</p>
<p>数，和我们普通的函数没有区别。</p>
<h4 id="线程的实现"><a href="#线程的实现" class="headerlink" title="线程的实现"></a>线程的实现</h4><p>⼀个 Java 线程的创建本质上就对应了⼀个本地线程（native thread）的创建，两者是⼀⼀对应的。</p>
<p>关键问题是：本地线程执⾏的应该是本地代码，⽽ Java 线程提供的线程函数（run）是 Java ⽅法，编译出的</p>
<p>是 Java 字节码，</p>
<p>所以， Java 线程其实提供了⼀个统⼀的线程函数，该线程函数通过 Java 虚拟机调⽤ Java 线程⽅法 , 这是通</p>
<p>过 Java 本地⽅法调⽤来实现的。</p>
<p><strong>以下是Thread的start方法示例</strong></p>
<p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726814478434-703be79a-c5db-48d1-8fce-be112314bb32.png" alt></p>
<p>可以看到它实际上调⽤了本地⽅法 <code>start0</code>, ⽽<code>start0</code>声明如下：</p>
<p><code>private native void start0();</code></p>
<p>也就是新创建的线程启动调⽤<code>native start0</code>⽅法，⽽这些<code>native</code>⽅法的注册是在<code>Thread</code>对象初始化的时候完成的，look：</p>
<p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726814632040-0ab55f30-f994-4cf6-a8dd-866740250c8f.png" alt></p>
<p><code>Thread</code> 类有个 <code>registerNatives</code> 本地⽅法，该⽅法主要的作⽤就是注册⼀些本地⽅法供 Thread 类使⽤，如<code>start0()</code>，<code>stop0()</code> 等等，可以说，所有操作本地线程的本地⽅法都是由它注册的。</p>
<p>这个⽅法放在⼀个 <code>static</code>语句块中，当该类被加载到 JVM 中的时候，它就会被调⽤，进⽽注册相应的本地⽅</p>
<p>法。⽽本地⽅法 <code>registerNatives</code> 是定义在<code>Thread.c</code> ⽂件中的。<code>Thread.c</code> 是个很⼩的⽂件，它定义了各个操作系统平台都要⽤到的关于线程的公⽤数据和操作。</p>
<h4 id="Java线程的调用关系"><a href="#Java线程的调用关系" class="headerlink" title="Java线程的调用关系"></a>Java线程的调用关系</h4><p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726814740885-2a47eae2-0a41-4a6d-9214-6d62a798bae9.png" alt></p>
<p><strong>第一种：</strong> 继承<code>Thread</code>，并重写<code>Thread</code>的<code>run</code>⽅法，启动过程为：<code>thread.start()</code>–&gt;中间过程– &gt;<code>&lt;font style=&quot;background-color:#DF2A3F;&quot;&gt;thread.run()&lt;/font&gt;</code>。  </p>
<p><strong>第二种：</strong> 实例化<code>Thread</code>，传递⼀个<code>Runable</code>任务，启动过程为：<code>thread.start()</code>–&gt;中间过程– &gt;<code>&lt;font style=&quot;background-color:#DF2A3F;&quot;&gt;thread.run()&lt;/font&gt;</code>–&gt;<code>runable.run()</code>。  </p>
<p>注意两处标红的<code>thread.run()</code>，此<code>run</code>⾮彼<code>run</code>。第⼀处<code>run</code>⽅法已经被我们重写了，是真正的业务逻辑，而第⼆处是<code>Thread</code>类⾥⾯的默认逻辑，他会调⽤<code>runable.run()</code>⽅法，业务逻辑都在<code>runable.run()</code>⾥⾯。这样看来仅仅是<code>JDK</code>的内部逻辑处理有点差异，对我们来说没有任何影响，喜欢哪种⽅式就⽤哪种。</p>
<h2 id="线程常用方法"><a href="#线程常用方法" class="headerlink" title="线程常用方法"></a>线程常用方法</h2><table>
<thead>
<tr>
<th>方法</th>
<th>功能</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>public void start()</td>
<td>启动⼀个新线程；Java虚拟 机调⽤此线程的run⽅法</td>
<td>start ⽅法只是让线程进⼊就 绪，⾥⾯代码不⼀定⽴刻 运 ⾏（CPU 的时间⽚还没分给 它）。每个线程对象的 start ⽅法只能调⽤⼀次，如果调⽤ 了多次会出现 IllegalThreadStateException</td>
</tr>
<tr>
<td>public void run()</td>
<td>线程启动后调⽤该⽅法</td>
<td>如果在构造 Thread 对象时传 递了 Runnable 参数，则 线 程启动后会调⽤ Runnable 中 的 run ⽅法，否则默 认不执 ⾏任何操作。但可以创建 Thread 的⼦类对象， 来覆盖 默认⾏为</td>
</tr>
<tr>
<td>public void setName(String name)</td>
<td>给当前线程取名字</td>
<td></td>
</tr>
<tr>
<td>public void getName()</td>
<td>获取当前线程的名字。线程存 在默认名称：⼦线程是 Thread-索引，主线程是 main</td>
<td></td>
</tr>
<tr>
<td>public static Thread currentThread()</td>
<td>获取当前线程对象，代码在哪 个线程中执⾏</td>
<td></td>
</tr>
<tr>
<td>public static void sleep(long time)</td>
<td>让当前线程休眠多少毫秒再继 续执⾏。Thread.sleep(0) : 让操作系统⽴刻重新进⾏⼀次 cpu竞争</td>
<td></td>
</tr>
<tr>
<td>public static native void yield()</td>
<td>提示线程调度器尽⼒让出当前 线程对CPU的使⽤</td>
<td>主要是为了测试和调试</td>
</tr>
<tr>
<td>public final int getPriority()</td>
<td>返回此线程的优先级</td>
<td></td>
</tr>
<tr>
<td>public final void setPriority(int priority)</td>
<td>更改此线程的优先级，常⽤1 5 10</td>
<td>java中规定线程优先级是1~10 的整数，较⼤的优先级 能提 ⾼该线程被 CPU 调度的机率</td>
</tr>
<tr>
<td>public void interrupt()</td>
<td>中断这个线程，异常处理机制</td>
<td></td>
</tr>
<tr>
<td>public static boolean interrupted()</td>
<td>判断当前线程是否被打断，清 除打断标记</td>
<td></td>
</tr>
<tr>
<td>public boolean isInterrupted()</td>
<td>判断当前线程是否被打断，不 清除打断标记</td>
<td></td>
</tr>
<tr>
<td>public final void join()</td>
<td>等待这个线程结束</td>
<td></td>
</tr>
<tr>
<td>public final void join(long millis)</td>
<td>等待这个线程死亡millis毫 秒，0意味着永远等待</td>
<td></td>
</tr>
<tr>
<td>public final native boolean isAlive()</td>
<td>线程是否存活（还没有运⾏完 毕）</td>
<td></td>
</tr>
<tr>
<td>public final void setDaemon(boolean on)</td>
<td>将此线程标记为守护线程或⽤ 户线程</td>
<td></td>
</tr>
<tr>
<td>public long getId()</td>
<td>获取线程⻓整型 的 id</td>
<td>id唯一</td>
</tr>
<tr>
<td>public state getState()</td>
<td>获取线程状态</td>
<td>Java 中线程状态是⽤ 6 个 enum 表示，分别为： NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED</td>
</tr>
</tbody></table>
<h3 id="start-与-run"><a href="#start-与-run" class="headerlink" title="start 与 run"></a>start 与 run</h3><p><strong>类型</strong></p>
<p>run方法是同步方法，而start方法是异步方法</p>
<p><strong>作用</strong></p>
<p>run方法的作用是存放任务代码，而start方法是启动线程</p>
<p><strong>线程数量方面</strong></p>
<p>执行run方法它不会产生新线程，而执行start方法会创建新的线程</p>
<p><strong>调用次数</strong></p>
<p>run方法会被执行无数次，而start方法只能执行一次，原因就在于线程不能被重复被启动</p>
<h3 id="线程的休眠"><a href="#线程的休眠" class="headerlink" title="线程的休眠"></a>线程的休眠</h3><p>使⽤线程的 sleep() 可以使线程休眠指定的毫秒数,在休眠结束的时候继续执⾏线程 示例：  、</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SleepThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            String[] names = <span class="keyword">new</span> String[]&#123;<span class="string">"zs"</span>, <span class="string">"ls"</span>, <span class="string">"ww"</span>, <span class="string">"z6"</span>&#125;;</span><br><span class="line">            <span class="keyword">int</span> index = (<span class="keyword">int</span>) (Math.random() * <span class="number">4</span>);</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">3</span>; i &gt; <span class="number">0</span>; i--) &#123;</span><br><span class="line">                System.out.println(i);</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(<span class="string">"倒计时："</span> + i);</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">"抽中学员为:"</span> + names[index]);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p> 测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestSleep</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span></span><br><span class="line"><span class="function"> </span>&#123;</span><br><span class="line"> <span class="keyword">new</span> SleepThread().start();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>其它线程可以使⽤ <code>interrupt</code> ⽅法打断正在睡眠的线程，这时 <code>sleep</code> ⽅法会抛出 <code>InterruptedException</code> </li>
<li>建议⽤ <code>TimeUnit</code> 的 <code>sleep</code> 代替 <code>Thread</code> 的 sleep 来获得更好的可读性 。其底层还是sleep⽅ 法</li>
<li>在循环访问锁的过程中，可以加⼊<code>sleep</code>让线程阻塞时间，防⽌⼤量占⽤cpu资源。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span>(<span class="keyword">true</span>) &#123;</span><br><span class="line">     <span class="keyword">try</span> &#123;</span><br><span class="line">         Thread.sleep( <span class="number">10000</span> );</span><br><span class="line">             &#125; <span class="keyword">catch</span>( InterruptedException ex ) &#123;</span><br><span class="line">                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 <span class="comment">// continue and check the flag</span></span><br><span class="line">                                                                                                                                                                                                                                         &#125;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<h3 id="线程的让步"><a href="#线程的让步" class="headerlink" title="线程的让步"></a>线程的让步</h3><ul>
<li><code>Thread.yield()</code> ⽅法作⽤是：暂停当前正在执⾏的线程对象（及放弃当前拥有的cup资 源）， 并执⾏其他线程。  </li>
<li><code>yield()</code>做的是让当前运⾏线程回到可运⾏状态，以允许具有相同优先级的其他线程获得运⾏ 机 会。因此，使⽤<code>yield()</code> 的⽬的是让相同优先级的线程之间能适当的轮转执⾏。但是，实际 中⽆ 法保证 yield() 达到让步⽬的，因为让步的线程还有可能被线程调度程序再次选中。</li>
</ul>
<blockquote>
<p> yield()⽅法并不能保证线程⼀定会让出CPU资源，它只是⼀个提示，告诉调度器当前线程愿意 让出CPU资源。具体是否让出CPU资源，还是由调度器决定。    </p>
</blockquote>
<p>示例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Task1</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</span><br><span class="line">     <span class="meta">@Override</span></span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">         <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>;i &lt; <span class="number">200</span>;i++)&#123;</span><br><span class="line">             System.out.println(<span class="string">"A:"</span>+i);</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Task2</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</span><br><span class="line">     <span class="meta">@Override</span></span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">         <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>;i &lt; <span class="number">10</span>;i++)&#123;</span><br><span class="line">             System.out.println(<span class="string">"B:"</span>+i);</span><br><span class="line">             Thread.yield();</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Demo</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">     <span class="keyword">new</span> Thread(																																																																						<span class="keyword">new</span> Task2()).start();</span><br><span class="line">     <span class="keyword">new</span> Thread(<span class="keyword">new</span> Task1()).start();</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>sleep()</code>和<code>yield()</code>的区别 <code>sleep()</code>使当前线程进⼊停滞状态，所以执⾏<code>sleep()</code>的线程在指定的时间内肯定不会被执⾏；<code>yield()</code>只是使当前线程重新回到可执⾏状态，所以执⾏<code>yield()</code>的线程有可能在进⼊到可执⾏状态后 ⻢上⼜被执⾏。</p>
<p><code>sleep</code> ⽅法使当前运⾏中的线程睡眼⼀段时间，进⼊不可运⾏状态，这段时间的⻓短是由程序设 定的，</p>
<p><code>yield</code> ⽅法使当前线程让出 <code>CPU</code> 占有权，但让出的时间是不可设定的。实际上，<code>yield()</code>⽅ 法对应了如下</p>
<p>操作：先检测当前是否有相同优先级的线程处于同可运⾏状态，如有，则把 CPU 的占有权交给此线程，</p>
<p>否则，继续运⾏原来的线程。所以<code>yield()</code>⽅法称为“退让”，它把运⾏机会 让给了同等优先级的其他线程</p>
<p>另外，<code>sleep</code> ⽅法允许较低优先级的线程获得运⾏机会，但 <code>yield()</code> ⽅法执⾏时，当前线程仍处在 可运</p>
<p>⾏状态，所以，不可能让出较低优先级的线程些时获得 <code>CPU</code> 占有权。在⼀个运⾏系统中， 如果较⾼优</p>
<p>先级的线程没有调⽤ <code>sleep</code> ⽅法，⼜没有受到 I<code>\O</code> 阻塞，那么，较低优先级线程只能 等待所有较⾼优先</p>
<p>级的线程运⾏结束，才有机会运⾏。 </p>
<h3 id="线程的优先级"><a href="#线程的优先级" class="headerlink" title="线程的优先级"></a>线程的优先级</h3><ul>
<li>我们可以通过传递参数给线程的<code>setPriority()</code> 来设置线程的优先级别 调整线程优先级：Java线程有优先级</li>
<li>优先级⾼的线程会获得较多的运⾏机会。优先级 : 只能反 映 线程 的 中或者是 紧急程度 , 不能决定 是否⼀定先执⾏  </li>
</ul>
<p>Java线程的优先级⽤整数表示，取值范围是1~10，Thread类有以下三个静态常量：  </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">int</span> MAX_PRIORITY</span><br><span class="line">线程可以具有的最⾼优先级，取值为<span class="number">10</span>。</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">int</span> MIN_PRIORITY</span><br><span class="line">线程可以具有的最低优先级，取值为<span class="number">1</span>。</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">int</span> NORM_PRIORITY</span><br><span class="line">分配给线程的默认优先级，取值为<span class="number">5</span>。</span><br></pre></td></tr></table></figure>

<p>示例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* 优先级</span></span><br><span class="line"><span class="comment">*</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PriorityThread</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>&#123;</span><br><span class="line">     <span class="meta">@Override</span></span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">         <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;<span class="number">50</span>;i++) &#123;</span><br><span class="line">             System.out.println(Thread.currentThread().getName()+<span class="string">"============"</span>+i);</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestPriority</span> </span>&#123;</span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">         PriorityThread p1=<span class="keyword">new</span> PriorityThread();</span><br><span class="line">         p1.setName(<span class="string">"p1"</span>);</span><br><span class="line">         PriorityThread p2=<span class="keyword">new</span> PriorityThread();</span><br><span class="line">         p2.setName(<span class="string">"p2"</span>);</span><br><span class="line">         PriorityThread p3=<span class="keyword">new</span> PriorityThread();</span><br><span class="line">         p3.setName(<span class="string">"p3"</span>);</span><br><span class="line">         p1.setPriority(<span class="number">1</span>);</span><br><span class="line">         p3.setPriority(<span class="number">10</span>);</span><br><span class="line">         <span class="comment">//启动</span></span><br><span class="line">         p1.start();</span><br><span class="line">         p2.start();</span><br><span class="line">         p3.start();</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="线程打断"><a href="#线程打断" class="headerlink" title="线程打断"></a>线程打断</h3><ul>
<li><code>public void interrupt()</code></li>
</ul>
<blockquote>
<p> 实例⽅法interrupt()仅仅是设置线程的中断状态为true，不会停⽌线程。  </p>
</blockquote>
<ul>
<li><code>public boolean isInterrupted()</code></li>
</ul>
<blockquote>
<p> 通过检查中断标志位，判断当前线程是否被中断。  </p>
</blockquote>
<ul>
<li><code>public static boolean interrupted()</code></li>
</ul>
<blockquote>
<p> 静态⽅法，判断线程是否被中断，并清除当前中断状态 也就是说这个⽅法做了两件事：</p>
<p>1、返回当前线程的中断状态 </p>
<p>2、将当前线程的中断状态设为false  </p>
</blockquote>
<h4 id="当前线程的中断标识为true，就⽴刻停⽌了吗？"><a href="#当前线程的中断标识为true，就⽴刻停⽌了吗？" class="headerlink" title="当前线程的中断标识为true，就⽴刻停⽌了吗？"></a>当前线程的中断标识为true，就⽴刻停⽌了吗？</h4><p> 先说结论：中断只是⼀种协同机制，只修改中断标识位⽽已，不会⽴刻停⽌线程 </p>
<ul>
<li>代码证明：</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Thread thread = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">     <span class="keyword">while</span> (<span class="keyword">true</span>)&#123;</span><br><span class="line">         System.out.println(<span class="string">"循环输出"</span>);</span><br><span class="line">     &#125;</span><br><span class="line">     &#125;);</span><br><span class="line">     thread.start();</span><br><span class="line">     thread.interrupt();</span><br></pre></td></tr></table></figure>

<p> 可以发现⼀直在输出： 循环输出…  </p>
<h4 id="如何使⽤中断标识优雅的停⽌线程？"><a href="#如何使⽤中断标识优雅的停⽌线程？" class="headerlink" title="如何使⽤中断标识优雅的停⽌线程？"></a>如何使⽤中断标识优雅的停⽌线程？</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">m3</span><span class="params">()</span> </span>&#123;</span><br><span class="line">     Thread t1 = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">     <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">         <span class="comment">//当前线程判断中断标志</span></span><br><span class="line">         <span class="keyword">if</span> (Thread.currentThread().isInterrupted()) &#123;</span><br><span class="line">             System.out.println(<span class="string">"-----程序结束------"</span>);</span><br><span class="line">             <span class="keyword">break</span>;</span><br><span class="line">         &#125;</span><br><span class="line">         System.out.println(<span class="string">"------hello------"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">     &#125;, <span class="string">"t1"</span>);</span><br><span class="line">     t1.start();</span><br><span class="line">     <span class="keyword">try</span> &#123;</span><br><span class="line">         TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">     &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">         e.printStackTrace();</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">         <span class="comment">//修改t1线程的中断标志位为true</span></span><br><span class="line">         t1.interrupt();</span><br><span class="line">     &#125;, <span class="string">"t2"</span>).start();</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<h3 id="线程的合并"><a href="#线程的合并" class="headerlink" title="线程的合并"></a>线程的合并</h3><p><code>Thread</code> 中，<code>join()</code>⽅法的作⽤是调⽤线程等待该线程完成后，才能继续往下运⾏。</p>
<p><code>join</code>是<code>Thread</code>类的⼀个⽅法，启动线程后直接调⽤，即<code>join()</code>的作⽤是：“等待该线程终⽌”，这⾥需 要理解的就是该线程是指的主线程等待⼦线程的终⽌。也就是在⼦线程调⽤了<code>join()</code>⽅法后⾯的代 码，只有等到⼦线程结束了才能执⾏。 </p>
<p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726817318884-a780f06f-a6f4-47a0-a848-0fbc2b4e0f70.png" alt></p>
<h4 id="为什么要⽤join-⽅法"><a href="#为什么要⽤join-⽅法" class="headerlink" title="为什么要⽤join()⽅法"></a>为什么要⽤join()⽅法</h4><p>在很多情况下，主线程⽣成并起动了⼦线程，如果⼦线程⾥要进⾏⼤量的耗时的运算，主线程往往 将于</p>
<p>⼦线程之前结束，但是如果主线程处理完其他的事务后，需要⽤到⼦线程的处理结果，也就是 主线程需</p>
<p>要等待⼦线程执⾏完成之后再结束，这个时候就要⽤到<code>join()</code>⽅法了。</p>
<p>示例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">JoinThread</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>&#123;</span><br><span class="line">    </span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="title">JoinThread</span><span class="params">(String name)</span></span>&#123;</span><br><span class="line">         <span class="keyword">super</span>(name);</span><br><span class="line">     &#125;</span><br><span class="line">    </span><br><span class="line">     <span class="meta">@Override</span></span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">         System.out.println(Thread.currentThread().getName()+<span class="string">"线程开始运⾏"</span>);</span><br><span class="line">         <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">             System.out.println(Thread.currentThread().getName()+<span class="string">"--&gt;⼦线程："</span>+i);</span><br><span class="line">         &#125;</span><br><span class="line">         System.out.println(Thread.currentThread().getName()+<span class="string">"线程结束运⾏"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JoinDemo</span> </span>&#123;</span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">         System.out.println(<span class="string">"主线程开始运⾏。。。"</span>);</span><br><span class="line">         JoinThread t1 = <span class="keyword">new</span> JoinThread(<span class="string">"新加⼊的线程"</span>);</span><br><span class="line">         t1.start();</span><br><span class="line">         <span class="comment">// try &#123;</span></span><br><span class="line">                 <span class="comment">// t1.join();</span></span><br><span class="line">         <span class="comment">// &#125; catch (InterruptedException e) &#123;</span></span><br><span class="line">                <span class="comment">// e.printStackTrace();</span></span><br><span class="line">         <span class="comment">// &#125;</span></span><br><span class="line">         System.out.println(<span class="string">"主线程开始结束。。。"</span>);</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="守护线程"><a href="#守护线程" class="headerlink" title="守护线程"></a>守护线程</h3><ul>
<li>默认情况下我们创建的线程都是⽤户线程（普通线程），进程需要等待所有的线程执⾏完毕后，进 程才会结束。  </li>
<li>守护线程<code>.setDaemon(true):</code>设置守护线程  </li>
<li>想要查看线程到底是⽤户线程还是守护线程，可以通过 <code>Thread.isDaemon()</code>⽅法来判断，如果返回 的结果是 true 则为守护线程，反之则为⽤户线程。  </li>
<li>当所有的⽤户线程退出后，守护线程会⽴⻢结束。</li>
</ul>
<p><strong>应用：</strong></p>
<p>垃圾回收器线程属于守护线程</p>
<p>tomcat⽤来接受处理外部的请求的线程就是守护线程。  </p>
<p>tomcat</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeamonThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">     <span class="meta">@Override</span></span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">         <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;<span class="number">50</span>;i++) &#123;</span><br><span class="line">             System.out.println(Thread.currentThread().getName()+<span class="string">"----------"</span>+i);</span><br><span class="line">             <span class="keyword">try</span> &#123;</span><br><span class="line">                 Thread.sleep(<span class="number">500</span>);</span><br><span class="line">             &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                 <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">                 e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestDeamon</span> </span>&#123;</span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">         <span class="comment">//创建线程(默认前台线程)</span></span><br><span class="line">         DeamonThread d1=<span class="keyword">new</span> DeamonThread();</span><br><span class="line">         <span class="comment">//设置线程为守护线程</span></span><br><span class="line">         d1.setDaemon(<span class="keyword">true</span>);<span class="comment">//主线程结束便结束了</span></span><br><span class="line">         d1.start();</span><br><span class="line">         <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;<span class="number">10</span>;i++) &#123;</span><br><span class="line">             System.out.println(<span class="string">"主线程:----------"</span>+i);</span><br><span class="line">             <span class="keyword">try</span> &#123;</span><br><span class="line">                 Thread.sleep(<span class="number">200</span>);</span><br><span class="line">             &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                 <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">                 e.printStackTrace();</span><br><span class="line">             &#125;</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="线程6种状态"><a href="#线程6种状态" class="headerlink" title="线程6种状态"></a>线程6种状态</h3><p>Java 线程在运⾏的⽣命周期中的指定时刻只可能处于下⾯ 6 种不同状态的其中⼀个状态</p>
<table>
<thead>
<tr>
<th>状态名称</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>NEW</td>
<td>初始状态,线程被构建,但是还没有调⽤start()⽅法</td>
</tr>
<tr>
<td>RUNNABLE</td>
<td>运⾏状态,Java线程将操作系统中的就绪和运⾏两 种状态统称为”运⾏中”</td>
</tr>
<tr>
<td>BLOCKED</td>
<td>阻塞状态,表示线程阻塞于锁</td>
</tr>
<tr>
<td>WAITING</td>
<td>等待状态,表示线程进⼊等待状态，进⼊该状态表 示当前线程需要其他线程通知(notify或者 notifyAll)</td>
</tr>
<tr>
<td>TIME_WAITING</td>
<td>超时等待状态,可以指定等待时间⾃⼰返回</td>
</tr>
<tr>
<td>TERMINATED</td>
<td>终⽌状态，表示当前线程已经执⾏完毕</td>
</tr>
</tbody></table>
<p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726817976227-6e81e8ea-45d7-4232-946f-d642610e11e6.png" alt></p>
<p>查看Thread类中定义了⼀个State枚举类型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> State &#123;</span><br><span class="line">     <span class="comment">/**</span></span><br><span class="line"><span class="comment">      * Thread state for a thread which has not yet started.</span></span><br><span class="line"><span class="comment">      */</span></span><br><span class="line">     NEW,</span><br><span class="line">    </span><br><span class="line">     RUNNABLE,</span><br><span class="line">    </span><br><span class="line">     BLOCKED,</span><br><span class="line">    </span><br><span class="line">     WAITING,</span><br><span class="line">    </span><br><span class="line">     TIMED_WAITING,</span><br><span class="line">    </span><br><span class="line">     TERMINATED;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="NEW"><a href="#NEW" class="headerlink" title="NEW"></a>NEW</h4><ul>
<li>⾸先我们展示⼀下整个线程状态的转换流程图，下⾯我们将进⾏详细的介绍讲解，如下图所示，我</li>
</ul>
<p>们可以直观的看到六种状态的转换，⾸先左侧上⽅是 <font style="color:#DF2A3F;">NEW </font>状态，这是创建新线程的状态，相当于</p>
<p>我们 <font style="color:#DF2A3F;">new Thread() </font>的过程。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test1</span><span class="params">()</span> </span>&#123; </span><br><span class="line">    <span class="comment">//NEW</span></span><br><span class="line">    Thread t1 = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">    System.out.println(<span class="string">"Thread1~~~~"</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    System.out.println(t1.getState());</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<ul>
<li><font style="color:#DF2A3F;">New</font> 表示线程被创建但尚未启动的状态：当我们⽤<font style="color:#DF2A3F;"> new Thread()</font> 新建⼀个线程时，如果线程没有开始运⾏ <font style="color:#DF2A3F;">start()</font>⽅法，那么线程也就没有开始执⾏ <font style="color:#DF2A3F;">run()</font> ⽅法⾥⾯的代码，那么此时它的状态就是<font style="color:#DF2A3F;">New</font>。⽽⼀旦线程调⽤了<font style="color:#DF2A3F;"> start()</font>，它的状态就会从 <font style="color:#DF2A3F;">New </font>变成 <font style="color:#DF2A3F;">Runnable</font>，进⼊到图中绿⾊的⽅框。</li>
</ul>
<h4 id="TERMINATED"><a href="#TERMINATED" class="headerlink" title="TERMINATED"></a>TERMINATED</h4><p><font style="color:#DF2A3F;">Terminated </font>终⽌状态，要想进⼊这个状态有两种可能。</p>
<ul>
<li>run() ⽅法执⾏完毕，线程正常退出 。</li>
<li>出现⼀个没有捕获的异常，终⽌了 run() ⽅法，最终导致意外终⽌。  </li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test2</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123; <span class="comment">//TERMINATED</span></span><br><span class="line">    Thread t1 = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">        System.out.println(<span class="string">"线程开始执⾏"</span>);</span><br><span class="line">        System.out.println(<span class="string">"线程结束执⾏"</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    t1.start();</span><br><span class="line">    Thread.sleep(<span class="number">3000</span>);</span><br><span class="line">    System.out.println(t1.getState());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>线程执⾏结束后查看状态为TERMINATED,加sleep是为了保证在getState的时候线程已经执⾏结束  </p>
<h4 id="RUNNABLE"><a href="#RUNNABLE" class="headerlink" title="RUNNABLE"></a>RUNNABLE</h4><ul>
<li><font style="color:#DF2A3F;">Java</font>中的<font style="color:#DF2A3F;">Runable</font> 状态对应操作系统线程状态中的两种状态，分别是 <font style="color:#DF2A3F;">Running</font> 和 <font style="color:#DF2A3F;">Ready</font>也就是说<font style="color:#DF2A3F;">Java</font>中处于 <font style="color:#DF2A3F;">Runnable</font> 状态的线程有可能正在执⾏，也有可能没有正在执⾏，正在等待被分配 CPU 资源。</li>
<li>所以，如果⼀个正在运⾏的线程是 <font style="color:#DF2A3F;">Runnable</font> 状态，当它运⾏到任务的⼀半时，执⾏该线程的 CPU被调度去做其他事情，导致该线程暂时不运⾏，它的状态依然不变，还是 <font style="color:#DF2A3F;">Runnable</font>，因为它有可能随时被调度回来继续执⾏任务。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test3</span><span class="params">()</span> </span>&#123; </span><br><span class="line">    <span class="comment">//RUNNABLE</span></span><br><span class="line">    Thread t1 = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">    &#125;);</span><br><span class="line">    t1.start();</span><br><span class="line">    System.out.println(t1.getState());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>上⾯认识了线程的关键状态 <font style="color:#DF2A3F;">Runnable</font> ，那么接下来我们来看⼀下下⾯的三个状态，这三个状态我 们可以统称为阻塞状态，它们分别是 <font style="color:#DF2A3F;">Blocked</font>(被阻塞)、<font style="color:#DF2A3F;">Waiting</font>(等待)、<font style="color:#DF2A3F;">Timed Waiting</font>(计时等待)。</li>
</ul>
<h4 id="BLOCKED"><a href="#BLOCKED" class="headerlink" title="BLOCKED"></a>BLOCKED</h4><p>这边我们模拟⼀个我们模拟找桌⼦⽤餐的场景 学⽣1和学⽣2同时争夺⼀个座位⽤餐，学⽣⼀先抢到座位，学⽣2就处于阻塞的状态，只能等待学⽣1⽤餐结束</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test1</span> </span>&#123;</span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">         System.out.println(Thread.currentThread().getName());</span><br><span class="line">         Table table = <span class="keyword">new</span> Table();</span><br><span class="line">         Thread student1 = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">             table.use();</span><br><span class="line">         &#125;, <span class="string">"s1"</span>);</span><br><span class="line">         Thread student2 = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">             table.use();</span><br><span class="line">         &#125;, <span class="string">"s2"</span>);</span><br><span class="line">         student1.start();</span><br><span class="line">         Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">         student2.start();</span><br><span class="line">         Thread.sleep(<span class="number">500</span>);</span><br><span class="line">         System.out.println(student2.getState());</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Table</span> </span>&#123;</span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">use</span><span class="params">()</span> </span>&#123;</span><br><span class="line">         System.out.println(Thread.currentThread().getName() + <span class="string">"-使⽤桌⼦"</span>);</span><br><span class="line">         <span class="keyword">try</span> &#123;</span><br><span class="line">             Thread.sleep(<span class="number">2000</span>);</span><br><span class="line">         &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">             e.printStackTrace();</span><br><span class="line">         &#125;</span><br><span class="line">         System.out.println(Thread.currentThread().getName() + <span class="string">"就餐结束"</span>);</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="WAITING"><a href="#WAITING" class="headerlink" title="WAITING"></a>WAITING</h4><p>上⾯我们看完阻塞状态，那么接下来我们了解⼀下 <font style="color:#DF2A3F;">Waiting</font> 状态，对于 <font style="color:#DF2A3F;">Waiting</font> 状态的进⼊有三种情况，如下图中所示，分别为：</p>
<ul>
<li><p>当线程中调⽤了没有设置 <font style="color:#DF2A3F;">Timeout</font> 参数的 <font style="color:#DF2A3F;">Object.wait()</font> ⽅法  </p>
</li>
<li><p>当线程调⽤了没有设置 <font style="color:#DF2A3F;">Timeout</font> 参数的<font style="color:#DF2A3F;"> Thread.join() </font>⽅法  </p>
</li>
<li><p>当线程调⽤了 <font style="color:#DF2A3F;">LockSupport</font>.<font style="color:#DF2A3F;">park()</font> ⽅法  </p>
<p>这边我们模拟学⽣1在得到座位后发现⾃⼰忘记点餐了，所以只能让出座位这个资源。进⼊wait状态</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test2</span> </span>&#123;</span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">         System.out.println(Thread.currentThread().getName());</span><br><span class="line">         Table1 table = <span class="keyword">new</span> Table1();</span><br><span class="line">         Thread student1 = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">             <span class="keyword">try</span> &#123;</span><br><span class="line">                 table.use();</span><br><span class="line">             &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                 e.printStackTrace();</span><br><span class="line">             &#125;</span><br><span class="line">         &#125;, <span class="string">"s1"</span>);</span><br><span class="line">         student1.start();</span><br><span class="line">         Thread.sleep(<span class="number">100</span>);</span><br><span class="line">         System.out.println(student1.getState());</span><br><span class="line">         Thread.currentThread().getState();</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Table1</span> </span>&#123;</span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">use</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">         System.out.println(Thread.currentThread().getName() + <span class="string">"-使⽤桌⼦"</span>);</span><br><span class="line">         <span class="comment">//忘记点餐了</span></span><br><span class="line">         System.out.println(<span class="string">"忘记点餐了"</span>);</span><br><span class="line">         wait(<span class="number">100</span>);</span><br><span class="line">         Thread.sleep(<span class="number">2000</span>);</span><br><span class="line">         System.out.println(Thread.currentThread().getName() + <span class="string">"就餐结束"</span>);</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li><font style="color:#DF2A3F;">Blocked</font>与<font style="color:#DF2A3F;">Waiting</font>的区别<ul>
<li><font style="color:#DF2A3F;">Blocked</font> 是在等待其他线程释放 <font style="color:#DF2A3F;">monitor</font> 锁</li>
<li><font style="color:#DF2A3F;">Waiting</font> 则是在等待某个条件，⽐如 <font style="color:#DF2A3F;">join</font> 的线程执⾏完毕，或者是 <font style="color:#DF2A3F;">notify()/notifyAll()</font> 。</li>
</ul>
</li>
</ul>
<h4 id="TIME-WAITING"><a href="#TIME-WAITING" class="headerlink" title="TIME_WAITING"></a>TIME_WAITING</h4><p>最后我们来说说这个 <font style="color:#DF2A3F;">Timed Waiting</font> 状态，它与 <font style="color:#DF2A3F;">Waiting</font> 状态⾮常相似，其中的区别只在于是否有<strong>时间的限制</strong>，在 <font style="color:#DF2A3F;">Timed Waiting</font> 状态时会等待超时，之后由系统唤醒，或者也可以提前被通知唤醒,如<font style="color:#DF2A3F;">notify</font></p>
<p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726819000502-c0e8f486-6782-4df7-9904-72154a17f9ac.png" alt></p>
<p>通过上述图我们可以看到在以下情况会让线程进⼊<font style="color:#DF2A3F;">Timed Waiting</font>状态。</p>
<ul>
<li>线程执⾏了设置了时间参数的 <font style="color:#DF2A3F;">Thread.sleep(long millis) </font>⽅法；</li>
<li>线程执⾏了设置了时间参数的 <font style="color:#DF2A3F;">Object.wait(long timeout)</font> ⽅法；</li>
<li>线程执⾏了设置了时间参数的 <font style="color:#DF2A3F;">Thread.join(long millis)</font> ⽅法；</li>
<li>线程执⾏了设置了时间参数的 <font style="color:#DF2A3F;">LockSupport.parkNanos(long nanos)</font> ⽅法和 <font style="color:#DF2A3F;">LockSupport.parkUntil(long deadline)</font> ⽅法。</li>
</ul>
<h3 id="线程状态间转换"><a href="#线程状态间转换" class="headerlink" title="线程状态间转换"></a>线程状态间转换</h3><p>上⾯我们讲了各⾃状态的特点和运⾏状态进⼊相应状态的情况 ，那么接下来我们将来分析各⾃状态之间 的转换，其实主要就是<font style="color:#DF2A3F;">Blocked</font>、<font style="color:#DF2A3F;">waiting</font>、<font style="color:#DF2A3F;">Timed Waiting</font>三种状态的转换 ，以及他们是如何进⼊下⼀ 状态最终进⼊ <font style="color:#DF2A3F;">Runnable</font> </p>
<p><font style="color:#DF2A3F;">Blocked</font> 进⼊ <font style="color:#DF2A3F;">Runnable</font> </p>
<ul>
<li>想要从 <font style="color:#DF2A3F;">Blocked</font> 状态进⼊ <font style="color:#DF2A3F;">Runnable</font> 状态，我们上⾯说过必须要线程获得 <font style="color:#DF2A3F;">monitor</font> 锁，但是如果想 进⼊其他状态那么就相对⽐较特殊，因为它是没有超时机制的，也就是不会主动进⼊。 </li>
</ul>
<p>如下图中紫⾊加粗表示线路：</p>
<p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726819262013-ae4fcb55-8680-48c5-9edc-32c6292db969.png" alt></p>
<p><font style="color:#DF2A3F;">Waiting</font> 进⼊ <font style="color:#DF2A3F;">Runnable</font></p>
<ul>
<li>只有当执⾏了<font style="color:#DF2A3F;">LockSupport.unpark()</font>，或者<font style="color:#DF2A3F;">join</font>的线程运⾏结束，或者被中断时才可以进⼊<font style="color:#DF2A3F;">Runnable</font> 状态。</li>
<li>如下图标注</li>
</ul>
<p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726819340723-cf47d9a5-f1e9-4106-ae79-b0ccbd511f48.png" alt></p>
<ul>
<li>如果通过其他线程调⽤ <font style="color:#DF2A3F;">notify() </font>或 <font style="color:#DF2A3F;">notifyAll()</font>来唤醒它，则它会直接进⼊ <font style="color:#DF2A3F;">Blocked</font> 状态，这⾥⼤家可能会有疑问，不是应该直接进⼊ <font style="color:#DF2A3F;">Runnable</font> 吗？这⾥需要注意⼀点 ，因为唤醒 <font style="color:#DF2A3F;">Waiting</font> 线程的线程如果调⽤ <font style="color:#DF2A3F;">notify()</font> 或 <font style="color:#DF2A3F;">notifyAll()</font>，要求必须⾸先持有该 <font style="color:#DF2A3F;">monitor</font> 锁，这也就是我们说的<font style="color:#DF2A3F;"> wait()</font>、<font style="color:#DF2A3F;">notify</font> 必须在 <font style="color:#DF2A3F;">synchronized</font> 代码块中。</li>
<li>所以处于 <font style="color:#DF2A3F;">Waiting</font> 状态的线程被唤醒时拿不到该锁，就会进⼊ <font style="color:#DF2A3F;">Blocked</font> 状态，直到执⾏<font style="color:#DF2A3F;">notify()/notifyAll() </font>的唤醒它的线程执⾏完毕并释放 <font style="color:#DF2A3F;">monitor</font> 锁，才可能轮到它去抢夺这把锁，如果它能抢到，就会从 <font style="color:#DF2A3F;">Blocked</font> 状态回到 <font style="color:#DF2A3F;">Runnable</font> 状态。</li>
</ul>
<p><font style="color:#DF2A3F;">Timed Waiting</font> 进⼊ <font style="color:#DF2A3F;">Runnable</font></p>
<ul>
<li>同样在<font style="color:#DF2A3F;">Timed Waiting</font>中执⾏<font style="color:#DF2A3F;">notify()</font>和<font style="color:#DF2A3F;">notifyAll()</font>也是⼀样的道理，它们会先进⼊<font style="color:#DF2A3F;">Blocked</font>状态，然后抢夺锁成功后，再回到 <font style="color:#DF2A3F;">Runnable</font>状态。 </li>
</ul>
<p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726819507586-e0ce7c70-c994-4361-8d81-ec41d95a8810.png" alt></p>
<ul>
<li>但是对于 <font style="color:#DF2A3F;">Timed Waiting</font> ⽽⾔，它存在超时机制，也就是说如果超时时间到了那么就会系统⾃动直 接拿到锁，或者当 <font style="color:#DF2A3F;">join</font>的线程执⾏结束/调⽤了<font style="color:#DF2A3F;">LockSupport.unpark()</font>/被中断等情况都会直接进⼊<font style="color:#DF2A3F;">Runnable</font>状态，⽽不会经历<font style="color:#DF2A3F;">Blocked</font>状态。</li>
</ul>
<p><img src="https://cdn.nlark.com/yuque/0/2024/png/34297780/1726819587869-1db54234-9bec-4d8b-81cb-eb23c4ef72ee.png" alt></p>
<p><strong>总结</strong></p>
<ul>
<li>线程的状态是按照箭头⽅向来⾛的，⽐如线程从 <font style="color:#DF2A3F;">New</font> 状态是不可以直接进⼊ <font style="color:#DF2A3F;">Blocked</font> 状态的，它 需要先经历 <font style="color:#DF2A3F;">Runnable</font> 状态。 </li>
<li>线程⽣命周期不可逆：⼀旦进⼊ <font style="color:#DF2A3F;">Runnable</font> 状态就不能回到 <font style="color:#DF2A3F;">New</font> 状态；⼀旦被终⽌就不可能再有任 何状态的变化。 </li>
<li>所以⼀个线程只能有⼀次 <font style="color:#DF2A3F;">New</font> 和 <font style="color:#DF2A3F;">Terminated</font> 状态，只有处于中间状态才可以相互转换。也就是这 两个状态不会参与相互转化。</li>
</ul>

      
    </div>
    
    
    

    

    
      <div>
        <div style="padding: 10px 0; margin: 20px auto; width: 90%; text-align: center;">
  <div>坚持原创技术分享，您的支持将鼓励我继续创作</div>
  <button id="rewardButton" disable="enable" onclick="var qr = document.getElementById('QR'); if (qr.style.display === 'none') {qr.style.display='block';} else {qr.style.display='none'}">
    <span>打赏</span>
  </button>
  <div id="QR" style="display: none;">

    
      <div id="wechat" style="display: inline-block">
        <img id="wechat_qr" src="/images/wechatpay.jpg" alt="老苏叶 微信支付"/>
        <p>微信支付</p>
      </div>
    

    
      <div id="alipay" style="display: inline-block">
        <img id="alipay_qr" src="/images/alipay.png" alt="老苏叶 支付宝"/>
        <p>支付宝</p>
      </div>
    

    

  </div>
</div>

      </div>
    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/%E7%BC%96%E7%A8%8B/" rel="tag"><i class="fa fa-tag"></i> 编程</a>
          
            <a href="/tags/Java/" rel="tag"><i class="fa fa-tag"></i> Java</a>
          
            <a href="/tags/JUC/" rel="tag"><i class="fa fa-tag"></i> JUC</a>
          
            <a href="/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" rel="tag"><i class="fa fa-tag"></i> 多线程</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2024/09/19/IDEA%E4%BF%AE%E6%94%B9%E8%BF%9C%E7%A8%8B%E5%88%86%E6%94%AF%E5%90%8D%E7%A7%B0/" rel="next" title="IDEA修改远程分支名称">
                <i class="fa fa-chevron-left"></i> IDEA修改远程分支名称
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  
    <div class="comments" id="comments">
    </div>
  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="/images/avatra.jpg"
                alt="老苏叶" />
            
              <p class="site-author-name" itemprop="name">老苏叶</p>
              <p class="site-description motion-element" itemprop="description">狂热的代码爱好者卑微的菜鸟程序员</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives">
              
                  <span class="site-state-item-count">25</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">37</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/tags/index.html">
                  <span class="site-state-item-count">35</span>
                  <span class="site-state-item-name">标签</span>
                </a>
              </div>
            

          </nav>

          
            <div class="feed-link motion-element">
              <a href="/rss2.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          
            <div class="links-of-author motion-element">
                
                  <span class="links-of-author-item">
                    <a href="https://github.com/By-laosuye/By-laosuye.github.io.git" target="_blank" title="GitHub">
                      
                        <i class="fa fa-fw fa-github"></i>GitHub</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="http://39.106.175.113" target="_blank" title="空间">
                      
                        <i class="fa fa-fw fa-vk"></i>空间</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="/qq" target="_blank" title="QQ">
                      
                        <i class="fa fa-fw fa-qq"></i>QQ</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="/weixin" target="_blank" title="微信">
                      
                        <i class="fa fa-fw fa-weixin"></i>微信</a>
                  </span>
                
            </div>
          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#进程、线程、纤程（携程）"><span class="nav-text">进程、线程、纤程（携程）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#什么是进程？"><span class="nav-text">什么是进程？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#什么是线程？"><span class="nav-text">什么是线程？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#什么是纤程（协程）？"><span class="nav-text">什么是纤程（协程）？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#总结"><span class="nav-text">总结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#并行、并发、串行"><span class="nav-text">并行、并发、串行</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#并发"><span class="nav-text">并发</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#并行"><span class="nav-text">并行</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#串行"><span class="nav-text">串行</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#总结-1"><span class="nav-text">总结</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#CPU的核心数和线程数的关系"><span class="nav-text">CPU的核心数和线程数的关系</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#上下文切换（Context-switch）"><span class="nav-text">上下文切换（Context switch）</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#创建线程"><span class="nav-text">创建线程</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#继承Thread"><span class="nav-text">继承Thread</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#实现Runnable"><span class="nav-text">实现Runnable</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#匿名内部类方式"><span class="nav-text">匿名内部类方式</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Lambda方式"><span class="nav-text">Lambda方式</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#线程执行的原理"><span class="nav-text">线程执行的原理</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#线程的实现"><span class="nav-text">线程的实现</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Java线程的调用关系"><span class="nav-text">Java线程的调用关系</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#线程常用方法"><span class="nav-text">线程常用方法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#start-与-run"><span class="nav-text">start 与 run</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#线程的休眠"><span class="nav-text">线程的休眠</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#线程的让步"><span class="nav-text">线程的让步</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#线程的优先级"><span class="nav-text">线程的优先级</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#线程打断"><span class="nav-text">线程打断</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#当前线程的中断标识为true，就⽴刻停⽌了吗？"><span class="nav-text">当前线程的中断标识为true，就⽴刻停⽌了吗？</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#如何使⽤中断标识优雅的停⽌线程？"><span class="nav-text">如何使⽤中断标识优雅的停⽌线程？</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#线程的合并"><span class="nav-text">线程的合并</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#为什么要⽤join-⽅法"><span class="nav-text">为什么要⽤join()⽅法</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#守护线程"><span class="nav-text">守护线程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#线程6种状态"><span class="nav-text">线程6种状态</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#NEW"><span class="nav-text">NEW</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#TERMINATED"><span class="nav-text">TERMINATED</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#RUNNABLE"><span class="nav-text">RUNNABLE</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#BLOCKED"><span class="nav-text">BLOCKED</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#WAITING"><span class="nav-text">WAITING</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#TIME-WAITING"><span class="nav-text">TIME_WAITING</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#线程状态间转换"><span class="nav-text">线程状态间转换</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      
       <div>
       <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=86 src="//music.163.com/outchain/player?type=2&id=30431643&auto=1&height=66"></iframe>
       </div>

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2024</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">老苏叶</span>

  
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-area-chart"></i>
    </span>
    
      <span class="post-meta-item-text">本站总字数&#58;</span>
    
    <span title="本站总字数">52.6k</span>
  
</div>









        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

  
    <span class="site-uv">
      <i class="fa fa-user"></i> 访问人数
      <span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
      
    </span>
  

  
    <span class="site-pv">
      <i class="fa fa-eye"></i> 访问总量
      <span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
      
    </span>
  
</div>








        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
          <span id="scrollpercent"><span>0</span>%</span>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  










  <script src="//unpkg.com/valine/dist/Valine.min.js"></script>
  
  <script type="text/javascript">
    var GUEST = ['nick','mail','link'];
    var guest = 'nick,mail,link';
    guest = guest.split(',').filter(item=>{
      return GUEST.indexOf(item)>-1;
    });
    new Valine({
        el: '#comments' ,
        verify: false,
        notify: true,
        appId: '4ePJvrPIyoMuyL54g1K6fNGc-gzGzoHsz',
        appKey: 'MKyiWYqHi0PIzxhH8jC1Q9pe',
        placeholder: '留下你的爪印吧～',
        avatar:'mm',
        guest_info:guest,
        pageSize:'10' || 10,
    });
  </script>



  

  <script type="text/javascript">
    // Popup Window;
    var isfetched = false;
    var isXml = true;
    // Search DB path;
    var search_path = "search.xml";
    if (search_path.length === 0) {
      search_path = "search.xml";
    } else if (/json$/i.test(search_path)) {
      isXml = false;
    }
    var path = "/" + search_path;
    // monitor main search box;

    var onPopupClose = function (e) {
      $('.popup').hide();
      $('#local-search-input').val('');
      $('.search-result-list').remove();
      $('#no-result').remove();
      $(".local-search-pop-overlay").remove();
      $('body').css('overflow', '');
    }

    function proceedsearch() {
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay"></div>')
        .css('overflow', 'hidden');
      $('.search-popup-overlay').click(onPopupClose);
      $('.popup').toggle();
      var $localSearchInput = $('#local-search-input');
      $localSearchInput.attr("autocapitalize", "none");
      $localSearchInput.attr("autocorrect", "off");
      $localSearchInput.focus();
    }

    // search function;
    var searchFunc = function(path, search_id, content_id) {
      'use strict';

      // start loading animation
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay">' +
          '<div id="search-loading-icon">' +
          '<i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>' +
          '</div>' +
          '</div>')
        .css('overflow', 'hidden');
      $("#search-loading-icon").css('margin', '20% auto 0 auto').css('text-align', 'center');

      $.ajax({
        url: path,
        dataType: isXml ? "xml" : "json",
        async: true,
        success: function(res) {
          // get the contents from search data
          isfetched = true;
          $('.popup').detach().appendTo('.header-inner');
          var datas = isXml ? $("entry", res).map(function() {
            return {
              title: $("title", this).text(),
              content: $("content",this).text(),
              url: $("url" , this).text()
            };
          }).get() : res;
          var input = document.getElementById(search_id);
          var resultContent = document.getElementById(content_id);
          var inputEventFunction = function() {
            var searchText = input.value.trim().toLowerCase();
            var keywords = searchText.split(/[\s\-]+/);
            if (keywords.length > 1) {
              keywords.push(searchText);
            }
            var resultItems = [];
            if (searchText.length > 0) {
              // perform local searching
              datas.forEach(function(data) {
                var isMatch = false;
                var hitCount = 0;
                var searchTextCount = 0;
                var title = data.title.trim();
                var titleInLowerCase = title.toLowerCase();
                var content = data.content.trim().replace(/<[^>]+>/g,"");
                var contentInLowerCase = content.toLowerCase();
                var articleUrl = decodeURIComponent(data.url);
                var indexOfTitle = [];
                var indexOfContent = [];
                // only match articles with not empty titles
                if(title != '') {
                  keywords.forEach(function(keyword) {
                    function getIndexByWord(word, text, caseSensitive) {
                      var wordLen = word.length;
                      if (wordLen === 0) {
                        return [];
                      }
                      var startPosition = 0, position = [], index = [];
                      if (!caseSensitive) {
                        text = text.toLowerCase();
                        word = word.toLowerCase();
                      }
                      while ((position = text.indexOf(word, startPosition)) > -1) {
                        index.push({position: position, word: word});
                        startPosition = position + wordLen;
                      }
                      return index;
                    }

                    indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false));
                    indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false));
                  });
                  if (indexOfTitle.length > 0 || indexOfContent.length > 0) {
                    isMatch = true;
                    hitCount = indexOfTitle.length + indexOfContent.length;
                  }
                }

                // show search results

                if (isMatch) {
                  // sort index by position of keyword

                  [indexOfTitle, indexOfContent].forEach(function (index) {
                    index.sort(function (itemLeft, itemRight) {
                      if (itemRight.position !== itemLeft.position) {
                        return itemRight.position - itemLeft.position;
                      } else {
                        return itemLeft.word.length - itemRight.word.length;
                      }
                    });
                  });

                  // merge hits into slices

                  function mergeIntoSlice(text, start, end, index) {
                    var item = index[index.length - 1];
                    var position = item.position;
                    var word = item.word;
                    var hits = [];
                    var searchTextCountInSlice = 0;
                    while (position + word.length <= end && index.length != 0) {
                      if (word === searchText) {
                        searchTextCountInSlice++;
                      }
                      hits.push({position: position, length: word.length});
                      var wordEnd = position + word.length;

                      // move to next position of hit

                      index.pop();
                      while (index.length != 0) {
                        item = index[index.length - 1];
                        position = item.position;
                        word = item.word;
                        if (wordEnd > position) {
                          index.pop();
                        } else {
                          break;
                        }
                      }
                    }
                    searchTextCount += searchTextCountInSlice;
                    return {
                      hits: hits,
                      start: start,
                      end: end,
                      searchTextCount: searchTextCountInSlice
                    };
                  }

                  var slicesOfTitle = [];
                  if (indexOfTitle.length != 0) {
                    slicesOfTitle.push(mergeIntoSlice(title, 0, title.length, indexOfTitle));
                  }

                  var slicesOfContent = [];
                  while (indexOfContent.length != 0) {
                    var item = indexOfContent[indexOfContent.length - 1];
                    var position = item.position;
                    var word = item.word;
                    // cut out 100 characters
                    var start = position - 20;
                    var end = position + 80;
                    if(start < 0){
                      start = 0;
                    }
                    if (end < position + word.length) {
                      end = position + word.length;
                    }
                    if(end > content.length){
                      end = content.length;
                    }
                    slicesOfContent.push(mergeIntoSlice(content, start, end, indexOfContent));
                  }

                  // sort slices in content by search text's count and hits' count

                  slicesOfContent.sort(function (sliceLeft, sliceRight) {
                    if (sliceLeft.searchTextCount !== sliceRight.searchTextCount) {
                      return sliceRight.searchTextCount - sliceLeft.searchTextCount;
                    } else if (sliceLeft.hits.length !== sliceRight.hits.length) {
                      return sliceRight.hits.length - sliceLeft.hits.length;
                    } else {
                      return sliceLeft.start - sliceRight.start;
                    }
                  });

                  // select top N slices in content

                  var upperBound = parseInt('1');
                  if (upperBound >= 0) {
                    slicesOfContent = slicesOfContent.slice(0, upperBound);
                  }

                  // highlight title and content

                  function highlightKeyword(text, slice) {
                    var result = '';
                    var prevEnd = slice.start;
                    slice.hits.forEach(function (hit) {
                      result += text.substring(prevEnd, hit.position);
                      var end = hit.position + hit.length;
                      result += '<b class="search-keyword">' + text.substring(hit.position, end) + '</b>';
                      prevEnd = end;
                    });
                    result += text.substring(prevEnd, slice.end);
                    return result;
                  }

                  var resultItem = '';

                  if (slicesOfTitle.length != 0) {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + highlightKeyword(title, slicesOfTitle[0]) + "</a>";
                  } else {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + title + "</a>";
                  }

                  slicesOfContent.forEach(function (slice) {
                    resultItem += "<a href='" + articleUrl + "'>" +
                      "<p class=\"search-result\">" + highlightKeyword(content, slice) +
                      "...</p>" + "</a>";
                  });

                  resultItem += "</li>";
                  resultItems.push({
                    item: resultItem,
                    searchTextCount: searchTextCount,
                    hitCount: hitCount,
                    id: resultItems.length
                  });
                }
              })
            };
            if (keywords.length === 1 && keywords[0] === "") {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>'
            } else if (resultItems.length === 0) {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'
            } else {
              resultItems.sort(function (resultLeft, resultRight) {
                if (resultLeft.searchTextCount !== resultRight.searchTextCount) {
                  return resultRight.searchTextCount - resultLeft.searchTextCount;
                } else if (resultLeft.hitCount !== resultRight.hitCount) {
                  return resultRight.hitCount - resultLeft.hitCount;
                } else {
                  return resultRight.id - resultLeft.id;
                }
              });
              var searchResultList = '<ul class=\"search-result-list\">';
              resultItems.forEach(function (result) {
                searchResultList += result.item;
              })
              searchResultList += "</ul>";
              resultContent.innerHTML = searchResultList;
            }
          }

          if ('auto' === 'auto') {
            input.addEventListener('input', inputEventFunction);
          } else {
            $('.search-icon').click(inputEventFunction);
            input.addEventListener('keypress', function (event) {
              if (event.keyCode === 13) {
                inputEventFunction();
              }
            });
          }

          // remove loading animation
          $(".local-search-pop-overlay").remove();
          $('body').css('overflow', '');

          proceedsearch();
        }
      });
    }

    // handle and trigger popup window;
    $('.popup-trigger').click(function(e) {
      e.stopPropagation();
      if (isfetched === false) {
        searchFunc(path, 'local-search-input', 'local-search-result');
      } else {
        proceedsearch();
      };
    });

    $('.popup-btn-close').click(onPopupClose);
    $('.popup').click(function(e){
      e.stopPropagation();
    });
    $(document).on('keyup', function (event) {
      var shouldDismissSearchPopup = event.which === 27 &&
        $('.search-popup').is(':visible');
      if (shouldDismissSearchPopup) {
        onPopupClose();
      }
    });
  </script>





  
  

  

  
  

  

  

  

</body>
</html>
